#include <blackbox/blackbox.h>

#ifdef BUOLA_HAVE_DC1394

#include "cdc1394.h"

namespace buola { namespace blackbox {

CDC1394::CDC1394()
    :   mDC1394(nullptr)
    ,   mCamNodes(nullptr)
{
    mDC1394=dc1394_new();

    if(dc1394_camera_enumerate(mDC1394,&mCamNodes)!=DC1394_SUCCESS)
    {
        throw XPermission("unable to find cameras");
    }

    if(mCamNodes->num==0)
    {
        throw XPermission("didn't find any camera");
    }

//    ResetBus();
}

CDC1394::~CDC1394()
{
    for(auto i=mCameras.begin();i!=mCameras.end();++i)
        delete i->second;
    mCameras.clear();

    if(mCamNodes)
        dc1394_camera_free_list(mCamNodes);

    if(mDC1394)
        dc1394_free(mDC1394);
}

void CDC1394::ResetBus()
{
    dc1394camera_t *lCam=dc1394_camera_new(mDC1394,mCamNodes->ids[0].guid);
    dc1394_reset_bus(lCam);
    dc1394_camera_free(lCam);

    dc1394_camera_free_list(mCamNodes);
    sleep(chrono::seconds(1));
    if(dc1394_camera_enumerate(mDC1394,&mCamNodes)!=DC1394_SUCCESS)
    {
        throw XPermission("unable to find cameras after resetting bus");
    }

    if(mCamNodes->num==0)
    {
        throw XPermission("didn't find any camera");
    }
}

CDC1394Camera *CDC1394::GetCamera(int pN)
{
    auto lIt=mCameras.find(pN);

    if(lIt!=mCameras.end()) return lIt->second;

    if (pN>=mCamNodes->num)
        throw XArgument("trying to get non-existent camera");

    CDC1394Camera *lCam=new CDC1394Camera(this,dc1394_camera_new(mDC1394,mCamNodes->ids[pN].guid));

    mCameras.insert(std::make_pair(pN,lCam));

    return lCam;
}

CDC1394Camera *CDC1394::GetCameraByUUID(uint64_t pUUID)
{
    for(int i=0;i<mCamNodes->num;i++)
    {
        if(mCamNodes->ids[i].guid==pUUID)
            return GetCamera(i);
    }

    throw XNotFound("trying to get non-existent camera by UUID");
}

CDC1394 *CDC1394::Get()
{
    static std::unique_ptr<CDC1394> lInstance(new CDC1394);

    return lInstance.get();
}

/*namespace blackbox*/ } /*namespace buola*/ }

#endif
